﻿#include "stdafx.h"
#include "sbhs.h"
#include "sbctn.h"
#include "kh_compiler.h"
#include "kh_code.h"

// 버전
static kint _sys_version(kScv* s)
{
	kint v[4];
	kvint iv;

	k_version(v);

	iv.w.l = (kushort)v[0];
	iv.w.h = (kushort)v[1];
	k_scv_push_int(s, iv.dw);

	return KRR_OK;
}

// 쓰기
static kint _sys_print(kScv* s)
{
	char* buf;
	kint len, arity, cnt, i;

	buf = (char*)alloca(1024);
	arity = k_scv_arity(s);

	for (cnt = i = 0; i < arity; i++)
	{
		kVar* va = k_scv_arg(s, i);
		const char* psz = k_var_tos(va, buf, 1024 - 1, &len);
		k_output_utf8(psz);
		cnt += len;
	}

	k_scv_push_int(s, cnt);

	return KRR_OK;
}

// 쓰기
static kint _sys_println(kScv* s)
{
	char* buf;
	kint len, arity, cnt, i;

	buf = (char*)alloca(1024);
	arity = k_scv_arity(s);

	for (cnt = i = 0; i < arity; i++)
	{
		kVar* va = k_scv_arg(s, i);
		const char* psz = k_var_tos(va, buf, 1024 - 1, &len);
		k_output_utf8(psz);
		cnt += len;
	}

	k_outputch('\n');

	k_scv_push_int(s, cnt + 1);

	return KRR_OK;
}

// 쓰기
static kint _sys_printp(kScv* s)
{
	char* buf;
	kint len, arity, cnt, i;

	buf = (char*)alloca(1024);
	arity = k_scv_arity(s);

	for (cnt = i = 0; i < arity; i++)
	{
		kVar* va = k_scv_arg(s, i);
		const char* psz = k_var_tos(va, buf, 1024 - 1, &len);
		k_mesg_utf8(psz);
		k_mesgch(' ');
		cnt += len + 1;
	}

	k_mesgch('\n');

	k_scv_push_int(s, cnt);

	return KRR_OK;
}

// 스택검사
static kint _sys_print_stack(kScv* s)
{
	khRealRnh* run;
	khRunInfo* ri;
	khCallInfo* ci;
	kDateTime dt;

	if (!k_var_safe_type(k_scv_at_ctnr(s), KTYPE_RNH, (kBase**)&run))
	{
		k_mesg("*stack: invalid container.\n");
		return KRR_OK;
	}

	k_now(&dt);
	k_mesgf("*enter: %04d-%02d-%02d %02d:%02d:%02d.%d\n", dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.millisecond);
	k_mesgf("*stack: size=%d, base=%d, top=%d\n", s->size, s->base, s->top);

	// 이거 어케?
	ri = run->rri;

	//
	for (ci = run->rci; ci; ci = ci->prev)
	{
		kRedFn* rfn = ci->rfn;

		if (!rfn)
			k_mesgf("    -> [base=%d]\n", ci->base);
		else
		{
			k_mesgf("    -> [%s, base=%d, addr=%Xh] (%s)\n",
				k_redfn_get_name(rfn), ci->base, ci->addr, k_redfn_get_filename(rfn));
		}
	}

	k_mesgf("*leave: ri=%p\n", ri);

	return KRR_OK;
}

// 포맷
static kint _sys_format(kScv* s)
{
	const char* fmt;
	kint arity;

	char* buf;
	kint blen;
	kint nth;

	kany64 av, am;
	char fi[3] = "% ";

	char tbuf[1024];
	kint tlen;
	kVar* va;

	arity = k_scv_arity(s);

	if (arity == 0)
		return KRR_ERROR;

	if (!k_var_conv_str(k_scv_arg(s, 0), &fmt, NULL))
		return KRR_ERROR;

	nth = 1;
	buf = (char*)alloca(2048);
	blen = 0;

	while (*fmt)
	{
		if (*fmt == '%')
		{
			if (arity <= nth)
			{
				if ((blen + 6) >= 2048 - 1)
					break;

				k_strcpy(buf + blen, "(null)");
				blen += 6;
				fmt += 2;
				continue;;
			}

			switch (fmt[1])
			{
				case 's':
					va = k_scv_arg(s, nth++);

					if (k_var_conv_str(va, (const char**)&av.s, &am.i))
					{
						if ((blen + am.i) >= 2048 - 1)
							goto pos_exitloop;

						k_strcpy(buf + blen, av.s);
						blen += am.i;
					}

					break;

				case 'S':
				case 'w':
					va = k_scv_arg(s, nth++);

					if (k_var_conv_wcs(va, (const kwchar**)&av.w, &am.i))
					{
						tlen = (kint)k_conv_uni_to_utf8(tbuf, 1024 - 1, av.w, am.i);

						if ((blen + tlen) >= 2048 - 1)
							goto pos_exitloop;

						k_strcpy(buf + blen, tbuf);
						blen += tlen;
					}

					break;

				case 'c':
				case 'd':
				case 'u':
				case 'x':
				case 'X':
					va = k_scv_arg(s, nth++);

					if (k_var_safe_int(va, &av.i))
					{
						fi[1] = fmt[1];
						tlen = k_snprintf(tbuf, 1024 - 1, fi, av.i);

						if ((blen + tlen) >= 2048 - 1)
							goto pos_exitloop;

						k_strcpy(buf + blen, tbuf);
						blen += tlen;
					}

					break;

				case 'p':
					va = k_scv_arg(s, nth++);

					if (k_var_safe_ptr(va, &av.p))
					{
						tlen = k_snprintf(tbuf, 1024 - 1, "%p", av.p);

						if ((blen + tlen) >= 2048 - 1)
							goto pos_exitloop;

						k_strcpy(buf + blen, tbuf);
						blen += tlen;
					}

					break;

				case 'f':
				case 'e':
				case 'g':
					va = k_scv_arg(s, nth++);

					if (k_var_safe_double(va, &av.dbl))
					{
						fi[1] = fmt[1];
						tlen = k_snprintf(tbuf, 1024 - 1, fi, av.dbl);

						if ((blen + tlen) >= 2048 - 1)
							goto pos_exitloop;

						k_strcpy(buf + blen, tbuf);
						blen += tlen;
					}

					break;

				case '%':
					if ((blen + 1) >= 2048 - 1)
						goto pos_exitloop;

					buf[blen++] = '%';
#if _SB_DEBUG_
					buf[blen] = '\0';
#endif

					break;
			}

			fmt += 2;
		}
		else
		{
			if ((blen + 1) >= 2048 - 1)
				break;

			buf[blen++] = *(fmt++);
#if _SB_DEBUG_
			buf[blen] = '\0';
#endif
		}
	}

pos_exitloop:
	if (blen > 0)
	{
		buf[blen] = '\0';
		k_scv_push_str(s, buf, blen);
	}

	return KRR_OK;
}

// 투스트링
static kint _sys_tos(kScv* s)
{
	kVar* va = k_scv_at_self(s);
	const char* psz;
	char* buf;
	kint len;

	if (k_var_is_null(va) && k_scv_arity(s) == 1)
		va = k_scv_arg(s, 0);

	buf = (char*)alloca(2048);
	psz = k_var_tos(va, buf, 2048 - 1, &len);

	k_scv_push_str(s, psz, len);

	return KRR_OK;
}

// 퍼블릭
static kint _sys_publics(kScv* s)
{
	if (k_scv_arity(s) == 0)
		k_scv_push(s, k_scv_at_pub(s));

	return KRR_OK;
}

// 시간
static kint _sys_tick(kScv* s)
{
	kbool bydbl;

	if (!k_scv_arg_bool(s, 0, &bydbl) || !bydbl)
		k_scv_push_int(s, (kint)k_gettick());
	else
		k_scv_push_double(s, k_curtick());

	return KRR_OK;
}

// 메모리 크기
static kint _sys_mem_size(kScv* s)
{
#ifndef SB_NO_MEM
	k_scv_push_long(s, (klong)k_heapsize());
#else
	k_scv_push_long(s, 0);
#endif

	return KRR_OK;
}

// 메모리 최대 크기
static kint _sys_mem_maximum(kScv* s)
{
#ifndef SB_NO_MEM
	k_scv_push_long(s, (klong)k_heapmax());
#else
	k_scv_push_long(s, 0);
#endif

	return KRR_OK;
}

//
kuint k_hlib_sys(kHsm* hsm)
{
	static struct khParamFuncReg mtds[] =
	{
#define MAPMTD(name)		KHPARAM_FUNC_REG_SIMPLE(K_STRING(name), K_CONCAT(_sys_,name))
#define MAPMNG(name,func)	KHPARAM_FUNC_REG_SIMPLE(name, K_CONCAT(_sys_,func))
		MAPMTD(version),
		MAPMTD(print),
		MAPMTD(println),
		MAPMTD(printp),
		MAPMTD(print_stack),
		MAPMTD(format),
		MAPMTD(tos),
		MAPMTD(publics),
		MAPMTD(tick),
		MAPMTD(mem_size),
		MAPMTD(mem_maximum),
		MAPMNG("tostring", tos),
#undef MAPMTD
#undef MAPMNG
	};

	if (k_hsm_reg_lib(hsm, KHLIB_SYSTEM))
		return 0;

	k_hsm_bind_libs(hsm, NULL, K_COUNTOF(mtds), mtds, NULL);

	return KHLIB_SYSTEM;
}
